home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume22 / nn6.4 / part12 < prev    next >
Encoding:
Internet Message Format  |  1990-06-07  |  54.2 KB

  1. Subject:  v22i047:  NN Newsreader, release 6.4, Part12/21
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: ca2064a3 2388034d b708a9ba bb673f97
  5.  
  6. Submitted-by: "Kim F. Storm" <storm@texas.dk>
  7. Posting-number: Volume 22, Issue 47
  8. Archive-name: nn6.4/part12
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  admin.c help/help.read inews/inews.c variable.c
  17. # Wrapped by storm@texas.dk on Sun May  6 18:19:49 1990
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. echo If this archive is complete, you will see the following message:
  20. echo '          "shar: End of archive 12 (of 22)."'
  21. if test -f 'admin.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'admin.c'\"
  23. else
  24.   echo shar: Extracting \"'admin.c'\" \(21406 characters\)
  25.   sed "s/^X//" >'admin.c' <<'END_OF_FILE'
  26. X/*
  27. X *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  28. X *
  29. X *    nnadmin - nn administator program
  30. X */
  31. X
  32. X#include <signal.h>
  33. X#include <errno.h>
  34. X#include "config.h"
  35. X#include "db.h"
  36. X#include "proto.h"
  37. X#include "term.h"
  38. X
  39. Ximport char
  40. X    *master_directory, *db_directory, *db_data_directory,
  41. X    *bin_directory, *news_directory, *news_lib_directory,
  42. X    *log_file, *news_active, *pager,
  43. X    group_path_name[];
  44. X
  45. Ximport char *exec_chdir_to;
  46. X
  47. X
  48. Xstatic char *pre_input;
  49. Xstatic int verbose = 1;
  50. X
  51. Xextern int group_completion();
  52. X
  53. X
  54. Xstatic get_cmd(prompt1, prompt2)
  55. Xchar *prompt1, *prompt2;
  56. X{
  57. X    char c;
  58. X
  59. X    if (s_hangup) {
  60. X    printf("\nnnmaster hangup\n");
  61. X    nn_exit(0);
  62. X    }
  63. X
  64. X    s_keyboard = 0;
  65. X
  66. X    if (pre_input) {
  67. X    if ((c = *pre_input++) == NUL)
  68. X        nn_exit(0);
  69. X    } else {
  70. X    do {
  71. X        if (prompt1) printf("\r%s\n", prompt1);
  72. X        if (prompt2) printf("\r%s >>>", prompt2);
  73. X        fl;
  74. X        raw();
  75. X        c = get_c();
  76. X        unset_raw();
  77. X        if (c == K_interrupt)
  78. X        s_keyboard++;
  79. X        else
  80. X        if (c == '!') {
  81. X        putchar(NL);
  82. X        if (exec_chdir_to != NULL)
  83. X            printf("\n\rDirectory: %s", exec_chdir_to);
  84. X        run_shell((char *)NULL, 0);
  85. X        } else
  86. X        printf("%c\n\n\r", c);
  87. X    } while (c == '!');
  88. X    }
  89. X
  90. X    if (islower(c))
  91. X    c = toupper(c);
  92. X
  93. X    return c;
  94. X}
  95. X
  96. X
  97. Xstatic long get_entry(prompt_str, min_val, max_val)
  98. Xchar *prompt_str;
  99. Xlong min_val, max_val;
  100. X{
  101. X    char buf[100];
  102. X    long val;
  103. X
  104. X loop:
  105. X
  106. X    printf("%s %ld..%ld (or all): ", prompt_str, min_val, max_val);
  107. X    fl;
  108. X    gets(buf);
  109. X    if (buf[0] == 'a' || buf[0] == NUL)
  110. X    return -1L;
  111. X
  112. X    val =  atol(buf);
  113. X    if (val < min_val || val > max_val) goto loop;
  114. X
  115. X    return val;
  116. X}
  117. X
  118. X
  119. Xstatic admin_confirm(action, must_confirm)
  120. Xchar *action;
  121. X{
  122. X    char buffer[100];
  123. X
  124. X    if (pre_input && !must_confirm) return 1;
  125. X
  126. X    sprintf(buffer, "Confirm %s  Y)es N)o", action);
  127. X
  128. X    return get_cmd((char *)NULL, buffer) == 'Y';
  129. X}
  130. X
  131. Xstatic char *get_groupname()
  132. X{
  133. X    char * groupname;
  134. X
  135. X    raw();
  136. X    printf("\n\n\r");
  137. X    prompt_line = Lines - 2;
  138. X    prompt("Group: ");
  139. X    fl;
  140. X    groupname = get_s(NONE, NONE, NONE, group_completion);
  141. X    unset_raw();
  142. X
  143. X    putchar(NL); putchar(CR);
  144. X
  145. X    if (groupname == NULL) return NULL;
  146. X
  147. X    if (groupname[0]) return groupname;
  148. X
  149. X    if (current_group == NULL) return NULL;
  150. X    if (current_group->group_flag & G_FOLDER) return NULL;
  151. X
  152. X    return current_group->group_name;
  153. X}
  154. X
  155. X
  156. Xstatic update_master()
  157. X{
  158. X    register group_header *gh;
  159. X    int ngp;
  160. X
  161. X    if (who_am_i != I_AM_ADMIN) {
  162. X    printf("Can only perform (U)pdate as nnadmin\n");
  163. X    return;
  164. X    }
  165. X
  166. X    ngp = master.number_of_groups;
  167. X
  168. X    open_master(OPEN_READ);
  169. X
  170. X    if (master.number_of_groups != ngp) {
  171. X    printf("\nNumber of groups changed from %d to %d\n",
  172. X           ngp, master.number_of_groups);
  173. X    }
  174. X
  175. X    ngp = 0;
  176. X
  177. X    Loop_Groups_Header(gh)
  178. X    if (update_group(gh) == -1) ngp++;
  179. X
  180. X    if (ngp) printf("There are %d blocked groups\n", ngp);
  181. X}
  182. X
  183. Xstatic find_files(gh)
  184. Xgroup_header *gh;
  185. X{
  186. X    char command[512], name[FILENAME], *db_data_path();
  187. X
  188. X    if (gh == NULL) {
  189. X    if (db_data_directory == NULL) {
  190. X        printf("Cannot list all files (they are scattered over the news partition)\n");
  191. X        return;
  192. X    }
  193. X    sprintf(command, "ls -l %s | %s", db_data_directory, pager);
  194. X    } else
  195. X    sprintf(command, "ls -l %s", db_data_path(name, gh, '*'));
  196. X    system(command);
  197. X}
  198. X
  199. Xstatic master_status()
  200. X{
  201. X    int cur_group, nblocked, nignored;
  202. X    long articles, disk_use;
  203. X    register group_header *gh;
  204. X
  205. X    printf("\nMaster:\n");
  206. X    printf("   initialized:   %s\n", date_time(master.db_created));
  207. X    printf("   last_scan:     %s\n", date_time(master.last_scan));
  208. X    printf("   last_size:     %ld\n", (long)master.last_size);
  209. X    printf("   no of groups:  %d\n", master.number_of_groups);
  210. X
  211. X    articles = disk_use = 0;
  212. X    nblocked = nignored = 0;
  213. X
  214. X    for (cur_group = 0; cur_group < master.number_of_groups; cur_group++) {
  215. X    gh = &active_groups[cur_group];
  216. X
  217. X#define DISK_BLOCKS(bytes) (((bytes) + 1023) / 1024)
  218. X
  219. X    disk_use += DISK_BLOCKS(gh->index_write_offset);
  220. X    disk_use += DISK_BLOCKS(gh->data_write_offset);
  221. X
  222. X    articles += gh->last_db_article - gh->first_db_article + 1;
  223. X
  224. X    if (gh->master_flag & M_BLOCKED) nblocked++;
  225. X    if (gh->master_flag & M_IGNORE_GROUP) nignored++;
  226. X    }
  227. X
  228. X    printf("\n   Articles:   %ld\n", articles);
  229. X    printf(  "   Disk usage: %ld k\n\n", disk_use);
  230. X
  231. X    if (nblocked) printf("Blocked groups: %3d\n", nblocked);
  232. X    if (nignored) printf("Ignored groups: %3d\n", nignored);
  233. X}
  234. X
  235. Xstatic dump_g_flag(gh)
  236. Xregister group_header *gh;
  237. X{
  238. X    printf("Flags: ");
  239. X    if (gh->master_flag & M_BLOCKED)     printf(" BLOCKED");
  240. X    if (gh->master_flag & M_EXPIRE)     printf(" EXPIRE");
  241. X    if (gh->master_flag & M_MODERATED)     printf(" MODERATED");
  242. X    if (gh->master_flag & M_CONTROL)     printf(" CONTROL");
  243. X    if (gh->master_flag & M_NO_DIRECTORY) printf(" NO_DIRECTORY");
  244. X    if (gh->master_flag & M_ALWAYS_DIGEST) printf(" ALWAYS_DIGEST");
  245. X    if (gh->master_flag & M_NEVER_DIGEST) printf(" NEVER_DIGEST");
  246. X    if (gh->master_flag & M_INCLUDE_OLD) printf(" INCL_OLD");
  247. X    if (gh->master_flag & M_AUTO_RECOLLECT) printf(" RECOLLECT");
  248. X    if (gh->master_flag & M_AUTO_ARCHIVE) printf(" ARCHIVE");
  249. X    if (gh->master_flag & M_IGNORE_GROUP) printf(" IGNORE");
  250. X    if (gh->master_flag & M_VALID) printf(" VALID");
  251. X    printf("\n");
  252. X}
  253. X
  254. Xstatic dump_m_entry(gh)
  255. Xregister group_header *gh;
  256. X{
  257. X    update_group(gh);
  258. X
  259. X    printf("\n%s\t%d\n", gh->group_name, gh->group_num);
  260. X    printf("first/last art: %06ld %06d\n",
  261. X       gh->first_db_article, gh->last_db_article);
  262. X    printf("   active info: %06ld %06d\n",
  263. X       gh->first_a_article, gh->last_a_article);
  264. X    printf("Offsets: index->%ld, data->%ld\n",
  265. X       gh->index_write_offset,
  266. X       gh->data_write_offset);
  267. X    if (gh->master_flag & M_AUTO_ARCHIVE)
  268. X    printf("Archive file: %s\n", gh->archive_file);
  269. X    if (gh->master_flag)
  270. X    dump_g_flag(gh);
  271. X}
  272. X
  273. X#define valerr( xxx , tp) { \
  274. X    if (verbose) { printf xxx ; fl; } \
  275. X    err_type = tp; \
  276. X    goto err; \
  277. X}
  278. X
  279. Xstatic validate_group(gh)
  280. Xgroup_header *gh;
  281. X{
  282. X    FILE *data, *ix;
  283. X    off_t data_offset, next_offset;
  284. X    cross_post_number cross_post;
  285. X    article_number cur_article;
  286. X    int n, err_type;
  287. X
  288. X    data = ix = NULL;
  289. X
  290. X    if (gh->first_db_article == (gh->last_db_article + 1)
  291. X    && gh->index_write_offset == 0)
  292. X    return 1;
  293. X
  294. X    if (verbose) { printf("\r%s: ", gh->group_name); clrline(); }
  295. X
  296. X    if (init_group(gh) <= 0) {
  297. X    printf("NO DIRECTORY (ok)");
  298. X    return 1; /* no directory/ignored */
  299. X    }
  300. X
  301. X    update_group(gh);
  302. X
  303. X    if (gh->master_flag & M_BLOCKED) {
  304. X    if (verbose) printf("BLOCKED (ok)\n");
  305. X    return 1;
  306. X    }
  307. X
  308. X    /*
  309. X     *    Check for major inconcistencies.
  310. X     *    Sometimes, news expire will reset article numbers
  311. X     *    to start from 0 again
  312. X     */
  313. X
  314. X    if (gh->last_db_article == 0) {
  315. X    return 1;
  316. X    }
  317. X
  318. X#ifdef RENUMBER_DANGER
  319. X    if (gh->first_a_article > (gh->last_db_article + 1) ||
  320. X    gh->last_db_article  > gh->last_a_article ||
  321. X    gh->first_db_article > gh->first_a_article) {
  322. X
  323. X    if (verbose)
  324. X        printf("RENUMBERING OF ARTICLES (active=%ld..%ld master=%ld..%ld)",
  325. X           gh->first_a_article, gh->last_a_article,
  326. X           gh->first_db_article, gh->last_db_article);
  327. X    err_type = 99;
  328. X    goto err;
  329. X    }
  330. X#endif
  331. X
  332. X    ix = open_data_file(gh, 'x', OPEN_READ);
  333. X    if (ix == NULL) valerr(("NO INDEX FILE"), 1);
  334. X
  335. X    data = open_data_file(gh, 'd', OPEN_READ);
  336. X    if (data == NULL) valerr(("NO DATA FILE"), 2);
  337. X
  338. X    cur_article = gh->first_db_article - 1;
  339. X
  340. X    while (cur_article <= gh->last_db_article) {
  341. X    if (s_hangup || s_keyboard) goto out;
  342. X
  343. X    data_offset = ftell(data);
  344. X
  345. X    switch (db_read_art(data)) {
  346. X     case 0:
  347. X        if (data_offset == gh->data_write_offset) goto out;
  348. X        valerr(("No header for article # %ld", (long)cur_article+1), 3);
  349. X     case 1:
  350. X        break;
  351. X     case -1:
  352. X        valerr(("END OF FILE on DATA FILE"), 4);
  353. X    }
  354. X
  355. X    if (db_hdr.dh_number <= 0 || cur_article > db_hdr.dh_number)
  356. X        valerr(("OUT OF SEQUENCE: %ld after %ld", (long)db_hdr.dh_number, (long)cur_article), 11);
  357. X
  358. X    if (cur_article < db_hdr.dh_number) {
  359. X        if (db_data.dh_type == DH_SUB_DIGEST)
  360. X        valerr(("NO DIGEST HEADER: %ld", (long)db_hdr.dh_number), 5);
  361. X
  362. X        do {
  363. X        cur_article++;
  364. X        if (!db_read_offset(ix, &next_offset))
  365. X            valerr(("NO INDEX FOR ARTICLE %ld", (long)cur_article), 6);
  366. X
  367. X        if (data_offset != next_offset)
  368. X            valerr(("OFFSET ERROR: %ld: %ld != %ld", (long)cur_article, (long)data_offset, (long)next_offset), 7);
  369. X        } while (cur_article < db_hdr.dh_number);
  370. X    }
  371. X
  372. X    for (n = 0; n < db_hdr.dh_cross_postings; n++) {
  373. X        cross_post = NETW_CROSS_INT(db_data.dh_cross[n]);
  374. X        if (cross_post < master.number_of_groups) continue;
  375. X        valerr(("CROSS POST RANGE ERROR: %ld (article # %ld)", (long)cross_post, (long)cur_article), 8);
  376. X    }
  377. X    }
  378. X
  379. X out:
  380. X    if (!s_keyboard && !s_hangup) {
  381. X    data_offset = ftell(data);
  382. X    if (data_offset != gh->data_write_offset)
  383. X        valerr(("DATA OFFSET %ld != %ld", (long)gh->data_write_offset, (long)data_offset), 9);
  384. X    data_offset = ftell(ix);
  385. X    if (data_offset != gh->index_write_offset)
  386. X        valerr(("INDEX OFFSET %ld != %ld", (long)gh->index_write_offset, (long)data_offset), 10);
  387. X    }
  388. X
  389. X    fclose(data);
  390. X    fclose(ix);
  391. X    if (verbose) printf("OK");
  392. X    return 1;
  393. X
  394. X err:
  395. X    if (data != NULL) fclose(data);
  396. X    if (ix != NULL) fclose(ix);
  397. X    log_entry('V', "%s: database error %d", gh->group_name, err_type);
  398. X    if (verbose) {
  399. X    putchar(NL);
  400. X    dump_m_entry(gh);
  401. X    }
  402. X
  403. X    if (!pre_input) {
  404. X    ding();
  405. X
  406. X    for (;;) {
  407. X        switch (get_cmd((char *)NULL,
  408. X"\nRepair group   Y)es N)o E)nter Q)uit")) {
  409. X         case 'Y':
  410. X        break;
  411. X         case 'N':
  412. X        return 0;
  413. X         case 'Q':
  414. X        s_keyboard++;
  415. X        return 0;
  416. X         case 'E':
  417. X        group_admin(gh);
  418. X        continue;
  419. X         default:
  420. X        continue;
  421. X        }
  422. X        break;
  423. X    }
  424. X    }
  425. X
  426. X    send_master(SM_RECOLLECT, gh, SP, 0L);
  427. X    return 0;
  428. X}
  429. X
  430. Xstatic dump_group(gh)
  431. Xgroup_header *gh;
  432. X{
  433. X    FILE *data, *ix;
  434. X    off_t offset;
  435. X    cross_post_number cross_post;
  436. X    article_number first_article;
  437. X    int n;
  438. X
  439. X    if (init_group(gh) <= 0)
  440. X    printf("cannot access group %s\n", gh->group_name);
  441. X
  442. X    update_group(gh);
  443. X
  444. X    first_article = get_entry("First article",
  445. X                  (long)gh->first_db_article,
  446. X                  (long)gh->last_db_article);
  447. X
  448. X    if (first_article < 0) first_article = gh->first_db_article;
  449. X    if (first_article <= 0) first_article = 1;
  450. X
  451. X    ix = open_data_file(gh, 'x', OPEN_READ);
  452. X    data = open_data_file(gh, 'd', OPEN_READ);
  453. X    if (ix == NULL || data == NULL) goto err;
  454. X
  455. X    fseek(ix, get_index_offset(gh, first_article), 0);
  456. X    if (!db_read_offset(ix, &offset)) goto err;
  457. X    fseek(data, offset, 0);
  458. X
  459. X    clrdisp();
  460. X    pg_init(1, 1);
  461. X
  462. X    for (;;) {
  463. X    if (s_hangup || s_keyboard) break;
  464. X
  465. X    if (pg_scroll(6)) {
  466. X        s_keyboard = 1;
  467. X        break;
  468. X    }
  469. X
  470. X    offset = ftell(data);
  471. X
  472. X    switch (db_read_art(data)) {
  473. X     case 0:
  474. X        goto out;
  475. X     case 1:
  476. X        break;
  477. X     case -1:
  478. X        goto err;
  479. X    }
  480. X
  481. X    printf("\noffset = %ld, article # = %ld",
  482. X           (long)offset, (long)(db_hdr.dh_number));
  483. X
  484. X    switch (db_data.dh_type) {
  485. X     case DH_DIGEST_HEADER:
  486. X        printf(" (digest header)\n");
  487. X        break;
  488. X     case DH_SUB_DIGEST:
  489. X        printf(" (digest sub-article)\n");
  490. X        break;
  491. X     case DH_NORMAL:
  492. X        putchar(NL);
  493. X        break;
  494. X    }
  495. X
  496. X    if (db_hdr.dh_cross_postings) {
  497. X        printf("xpost(%d):", db_hdr.dh_cross_postings);
  498. X
  499. X        for (n = 0; n < db_hdr.dh_cross_postings; n++) {
  500. X        cross_post = NETW_CROSS_INT(db_data.dh_cross[n]);
  501. X        printf(" %d", cross_post);
  502. X        }
  503. X        putchar(NL);
  504. X    }
  505. X
  506. X    printf("ts=%lu hp=%ld, fp=+%d, lp=%ld, ref=%d%s, lines=%d\n",
  507. X           (long unsigned)db_hdr.dh_date, (long)db_hdr.dh_hpos,
  508. X           (int)db_hdr.dh_fpos, (long)db_hdr.dh_lpos,
  509. X           db_hdr.dh_replies & 0x7f,
  510. X           (db_hdr.dh_replies & 0x80) ? "+Re" : "",
  511. X           db_hdr.dh_lines);
  512. X
  513. X    if (db_hdr.dh_sender_length)
  514. X        printf("Sender(%d): %s\n", db_hdr.dh_sender_length, db_data.dh_sender);
  515. X    else
  516. X        printf("No sender\n");
  517. X
  518. X    if (db_hdr.dh_subject_length)
  519. X        printf("Subj(%d): %s\n", db_hdr.dh_subject_length, db_data.dh_subject);
  520. X    else
  521. X        printf("No subject\n");
  522. X    }
  523. X
  524. X out:
  525. X    if (!s_keyboard && !s_hangup && ftell(data) != gh->data_write_offset)
  526. X    goto err;
  527. X
  528. X    fclose(data);
  529. X    fclose(ix);
  530. X    return 1;
  531. X
  532. X err:
  533. X    if (data != NULL) fclose(data);
  534. X    if (ix != NULL) fclose(ix);
  535. X    printf("\n*** DATABASE INCONSISTENCY DETECTED - run V)alidate\n");
  536. X    return 0;
  537. X}
  538. X
  539. Xstatic kill_master(term)
  540. Xint term;
  541. X{
  542. X    switch (proto_lock(I_AM_MASTER, term ? PL_TERMINATE : PL_WAKEUP_SOFT)) {
  543. X     case 1:
  544. X    if (verbose)
  545. X        printf("sent %s signal to master\n", term ? "termination" : "wakeup");
  546. X    break;
  547. X     case 0:
  548. X    printf("cannot signal master\n");
  549. X    break;
  550. X     case -1:
  551. X    if (verbose) printf("master is not running\n");
  552. X    break;
  553. X    }
  554. X}
  555. X
  556. Xstatic master_admin()
  557. X{
  558. X    register char c;
  559. X    int cur_group;
  560. X    long value;
  561. X    register group_header *gh;
  562. X
  563. X    exec_chdir_to = db_directory;
  564. X
  565. X    for (;;) {
  566. X    switch (c = get_cmd(
  567. X"\nD)ump F)iles G)roup K)ill O)ptions S)tat T)race",
  568. X"MASTER")) {
  569. X
  570. X     case 'G':
  571. X        cur_group = (int)get_entry("Group number",
  572. X                  0L, (long)(master.number_of_groups - 1));
  573. X        if (cur_group >= 0)
  574. X        dump_m_entry(&active_groups[cur_group]);
  575. X        break;
  576. X
  577. X     case 'D':
  578. X        do {
  579. X        c = get_cmd(
  580. X"\nA)ll B)locked E)mpty H)oles I)gnored N)on-empty V)alid in(W)alid",
  581. X"DUMP");
  582. X        cur_group = -1;
  583. X        pg_init(1, 1);
  584. X
  585. X        while (++cur_group < master.number_of_groups) {
  586. X            if (s_keyboard || s_hangup) break;
  587. X
  588. X            gh = &active_groups[cur_group];
  589. X#define NODUMP(cond) if (cond) continue; break
  590. X            switch (c) {
  591. X             case 'N':
  592. X            NODUMP(gh->index_write_offset == 0);
  593. X             case 'E':
  594. X            NODUMP(gh->index_write_offset != 0);
  595. X             case 'H':
  596. X            NODUMP(gh->first_a_article >= gh->first_db_article);
  597. X             case 'B':
  598. X            NODUMP((gh->master_flag & M_BLOCKED) == 0);
  599. X             case 'I':
  600. X            NODUMP((gh->master_flag & M_IGNORE_GROUP) == 0);
  601. X             case 'V':
  602. X            NODUMP((gh->master_flag & M_VALID) == 0);
  603. X             case 'W':
  604. X            NODUMP(gh->master_flag & M_VALID);
  605. X             default:
  606. X            s_keyboard = 1; continue;
  607. X            }
  608. X
  609. X            if (pg_scroll(6)) break;
  610. X            dump_m_entry(gh);
  611. X        }
  612. X        } while (!s_keyboard && !s_hangup);
  613. X        break;
  614. X
  615. X     case 'F':
  616. X        find_files((group_header *)NULL);
  617. X        break;
  618. X
  619. X     case 'O':
  620. X        c = get_cmd("r)epeat_delay  e)xpire_level", "OPTION");
  621. X        if (c != 'R' && c != 'E') break;
  622. X        value = get_entry("Option value", 1L, 10000L);
  623. X        if (value < 0) break;
  624. X        send_master(SM_SET_OPTION, (group_header *)NULL, tolower(c), value);
  625. X        break;
  626. X
  627. X     case 'S':
  628. X        master_status();
  629. X        break;
  630. X
  631. X     case 'T':
  632. X        send_master(SM_SET_OPTION, (group_header *)NULL, 't', -1L);
  633. X        break;
  634. X
  635. X     case 'K':
  636. X        if (admin_confirm("Stop nn Master", 0))
  637. X        kill_master(1);
  638. X        break;
  639. X
  640. X     default:
  641. X        exec_chdir_to = NULL;
  642. X        return;
  643. X    }
  644. X    }
  645. X}
  646. X
  647. X
  648. Xstatic log_admin()
  649. X{
  650. X    char command[FILENAME + 100], c;
  651. X
  652. X    if (pre_input && *pre_input == NUL) {
  653. X    c = SP;
  654. X    goto log_tail;
  655. X    }
  656. X
  657. X loop:
  658. X
  659. X    c = get_cmd(
  660. X"\n1-9)tail A)dm C)ollect E)rr N)ntp G)roup R)eport e(X)pire .)all @)clean",
  661. X"LOG");
  662. X
  663. X    if (c < SP || c == 'Q') return;
  664. X
  665. X    if (c == '@') {
  666. X    if (admin_confirm("Truncation", 0)) {
  667. X        sprintf(command, "%s.old", log_file);
  668. X        unlink(command);
  669. X        if (link(log_file, command) < 0) goto tr_failed;
  670. X        if (unlink(log_file) < 0) {
  671. X        unlink(command);
  672. X        goto tr_failed;
  673. X        }
  674. X        log_entry('A', "Log Truncated");
  675. X        chmod(log_file, 0666);
  676. X    }
  677. X    return;
  678. X
  679. X     tr_failed:
  680. X    printf("Truncation failed -- check permissions etc.\n");
  681. X    goto loop;
  682. X    }
  683. X
  684. X    if (c == 'G') {
  685. X    char *groupname;
  686. X
  687. X    if ((groupname = get_groupname()) == NULL) goto loop;
  688. X    sprintf(command, "fgrep '%s' %s | %s",
  689. X        groupname, log_file, pager);
  690. X    system(command);
  691. X
  692. X    goto loop;
  693. X    }
  694. X
  695. X log_tail:
  696. X    if (c == '$' || c == SP || isdigit(c)) {
  697. X    int n;
  698. X
  699. X    n = isdigit(c) ? 10 * (c - '0') : 10;
  700. X    sprintf(command, "tail -%d %s", n, log_file);
  701. X    system(command);
  702. X    goto loop;
  703. X    }
  704. X
  705. X    if (c == '*') {
  706. X    c = '.';
  707. X    }
  708. X
  709. X    sprintf(command, "grep '^%c:' %s | %s", c, log_file, pager);
  710. X    system(command);
  711. X
  712. X    goto loop;
  713. X}
  714. X
  715. X
  716. Xstatic flag_admin(gh, mode_str, set_flag)
  717. Xgroup_header *gh;
  718. Xchar *mode_str;
  719. Xint set_flag;
  720. X{
  721. X    char buffer[50];
  722. X    int new_flag = 0;
  723. X
  724. X    putchar(NL);
  725. X
  726. X    dump_g_flag(gh);
  727. X
  728. X    sprintf(buffer, "%s FLAG", mode_str);
  729. X
  730. X    switch (get_cmd(
  731. X"\nA)lways_digest N)ever_digest M)oderated C)ontrol no_(D)ir",
  732. Xbuffer)) {
  733. X
  734. X     default:
  735. X    return;
  736. X
  737. X     case 'M':
  738. X    new_flag = M_MODERATED;
  739. X    break;
  740. X
  741. X     case 'C':
  742. X    new_flag = M_CONTROL;
  743. X    break;
  744. X
  745. X     case 'D':
  746. X    new_flag = M_NO_DIRECTORY;
  747. X    break;
  748. X
  749. X     case 'A':
  750. X    new_flag = M_ALWAYS_DIGEST;
  751. X    break;
  752. X
  753. X     case 'N':
  754. X    new_flag = M_NEVER_DIGEST;
  755. X    break;
  756. X    }
  757. X
  758. X    if (new_flag & (M_CONTROL | M_NO_DIRECTORY))
  759. X    if (!admin_confirm("Flag Change", 0))
  760. X        new_flag = 0;
  761. X
  762. X    if (new_flag) {
  763. X    if (set_flag) {
  764. X        if (gh->master_flag & new_flag)
  765. X        new_flag = 0;
  766. X        else {
  767. X        send_master(SM_SET_FLAG, gh, 's', (long)new_flag);
  768. X        gh->master_flag |= new_flag;
  769. X        }
  770. X    } else {
  771. X        if ((gh->master_flag & new_flag) == 0)
  772. X        new_flag = 0;
  773. X        else {
  774. X        send_master(SM_SET_FLAG, gh, 'c', (long)new_flag);
  775. X        gh->master_flag &= ~new_flag;
  776. X        }
  777. X    }
  778. X    }
  779. X
  780. X    if (new_flag == 0)
  781. X    printf("NO CHANGE\n");
  782. X    else
  783. X    dump_g_flag(gh);
  784. X}
  785. X
  786. X
  787. Xstatic rmgroup(gh)
  788. Xgroup_header *gh;
  789. X{
  790. X    char command[FILENAME*2];
  791. X
  792. X    if (!file_exist(news_active, "w")) {
  793. X    printf("Not privileged to run rmgroup\n");
  794. X    return;
  795. X    }
  796. X
  797. X    sprintf(command, "%s/rmgroup %s", news_lib_directory, gh->group_name);
  798. X    system(command);
  799. X    any_key(0);
  800. X    gh->master_flag &= ~M_VALID;        /* just for nnadmin */
  801. X    gh->master_flag |= M_IGNORE_A;
  802. X}
  803. X
  804. Xstatic group_admin(gh)
  805. Xregister group_header *gh;
  806. X{
  807. X    char *groupname, gbuf[FILENAME], dirbuf[FILENAME];
  808. X
  809. X    if (gh != NULL) goto have_group;
  810. X
  811. X new_group:
  812. X    if ((groupname = get_groupname()) == NULL) return;
  813. X
  814. X    gh = lookup(groupname);
  815. X    if (gh == NULL) {
  816. X    printf("No group named %s\n", groupname);
  817. X    goto new_group;
  818. X    }
  819. X
  820. X have_group:
  821. X    if (!use_nntp && init_group(gh)) {
  822. X    strcpy(dirbuf, group_path_name);
  823. X    dirbuf[strlen(dirbuf)-1] = NUL;
  824. X    exec_chdir_to = dirbuf;
  825. X    }
  826. X
  827. X    sprintf(gbuf, "GROUP %s", gh->group_name);
  828. X
  829. X    for (;;) {
  830. X    switch (get_cmd(
  831. X"\nD)ata E)xpire F)iles G)roup H)eader R)ecollect V)alidate Z)ap",
  832. Xgbuf)) {
  833. X     case 'D':
  834. X        dump_group(gh);
  835. X        break;
  836. X
  837. X     case 'V':
  838. X        verbose = 1;
  839. X        validate_group(gh);
  840. X        putchar(NL);
  841. X        break;
  842. X
  843. X     case 'H':
  844. X        dump_m_entry(gh);
  845. X        break;
  846. X
  847. X     case 'F':
  848. X        find_files(gh);
  849. X        break;
  850. X
  851. X     case 'S':
  852. X        flag_admin(gh, "Set", 1);
  853. X        break;
  854. X
  855. X     case 'C':
  856. X        flag_admin(gh, "Clear", 0);
  857. X        break;
  858. X
  859. X     case 'R':
  860. X        if (admin_confirm("Recolletion of Group", 0))
  861. X        send_master(SM_RECOLLECT, gh, SP, 0L);
  862. X        break;
  863. X
  864. X     case 'Z':
  865. X        if (admin_confirm("Remove Group (run rmgroup)", 1))
  866. X        rmgroup(gh);
  867. X        break;
  868. X
  869. X     case 'E':
  870. X        if (admin_confirm("Expire Group", 0))
  871. X        send_master(SM_EXPIRE, gh, SP, 0L);
  872. X        break;
  873. X
  874. X     case 'G':
  875. X        goto new_group;
  876. X
  877. X     default:
  878. X        exec_chdir_to = NULL;
  879. X        return;
  880. X    }
  881. X    }
  882. X}
  883. X
  884. X
  885. Xstatic show_config()
  886. X{
  887. X#ifdef NNTP
  888. X    extern char nntp_server[];
  889. X#endif
  890. X
  891. X    printf("\nConfiguration:\n\n");
  892. X    printf("BIN:  %s\nLIB:  %s\nNEWS SPOOL: %s\nNEWS LIB: %s\n",
  893. X       bin_directory,
  894. X       lib_directory,
  895. X       news_directory,
  896. X       news_lib_directory);
  897. X
  898. X    printf("DB:   %s  %s\n", db_directory,
  899. X       db_data_directory != NULL ? db_data_directory :
  900. X       "(per-group files in group directories)");
  901. X
  902. X    printf("ACTIVE: %s\n", news_active);
  903. X
  904. X#ifdef NNTP
  905. X    if (use_nntp)
  906. X    printf("NNTP ACTIVE. server=%s\n", nntp_server);
  907. X    else
  908. X    printf("NNTP NOT ACTIVE\n");
  909. X#endif
  910. X
  911. X#ifdef NETWORK_DATABASE
  912. X    printf("Database is machine independent (network format).\n");
  913. X#ifdef NETWORK_BYTE_ORDER
  914. X    printf("Local system assumes to use network byte order\n");
  915. X#endif
  916. X#else
  917. X    printf("Database format is machine dependent (byte order and alignment)\n");
  918. X#endif
  919. X    printf("Database version: %d\n", NNDB_MAGIC & 0xff);
  920. X
  921. X#ifdef STATISTICS
  922. X    printf("Recording usage statistics\n");
  923. X#else
  924. X    printf("No usage statistics are recorded\n");
  925. X#endif
  926. X
  927. X    printf("Mail delivery program: %s\n", REC_MAIL);
  928. X#ifdef APPEND_SIGNATURE
  929. X    printf("Query for appending .signature ENABLED\n");
  930. X#else
  931. X    printf("Query for appending .signature DISABLED\n");
  932. X#endif
  933. X
  934. X    printf("Max pathname length is %d bytes\n", FILENAME-1);
  935. X}
  936. X
  937. X
  938. Xadmin_mode(input_string)
  939. Xchar *input_string;
  940. X{
  941. X    register group_header *gh;
  942. X    int was_raw = unset_raw();
  943. X
  944. X    if (input_string && *input_string) {
  945. X    pre_input = input_string;
  946. X    } else {
  947. X    pre_input = NULL;
  948. X    printf("\nMaster is%s running\n",
  949. X           proto_lock(I_AM_MASTER, PL_CHECK) < 0 ? " NOT" : "");
  950. X    }
  951. X
  952. X    for (;;) {
  953. X    switch(get_cmd(
  954. X"\nC)onf E)xpire G)roups I)nit L)og M)aster Q)uit S)tat U)pdate V)alidate W)akeup",
  955. X"ADMIN")) {
  956. X
  957. X     case 'M':
  958. X        master_admin();
  959. X        break;
  960. X
  961. X     case 'W':
  962. X        kill_master(0);
  963. X        break;
  964. X
  965. X     case 'E':
  966. X        if (admin_confirm("Expire All Groups", 1))
  967. X        send_master(SM_EXPIRE, (group_header *)NULL, SP, 0L);
  968. X        break;
  969. X
  970. X     case 'I':
  971. X        if (admin_confirm("INITIALIZATION, i.e. recollect all groups", 1))
  972. X        send_master(SM_RECOLLECT, (group_header *)NULL, SP, 0L);
  973. X        break;
  974. X
  975. X     case 'G':
  976. X        group_admin((group_header *)NULL);
  977. X        break;
  978. X
  979. X     case 'L':
  980. X        log_admin();
  981. X        break;
  982. X
  983. X     case 'S':
  984. X        master_status();
  985. X        break;
  986. X
  987. X     case 'C':
  988. X        show_config();
  989. X        break;
  990. X
  991. X     case 'U':
  992. X        update_master();
  993. X        break;
  994. X
  995. X     case 'Z':
  996. X        verbose = 0;
  997. X        /* FALL THRU */
  998. X
  999. X     case 'V':
  1000. X        Loop_Groups_Sorted(gh) {
  1001. X        if (s_hangup || s_keyboard) break;
  1002. X        validate_group(gh);
  1003. X        }
  1004. X        verbose = 1;
  1005. X        break;
  1006. X
  1007. X     case '=':
  1008. X        verbose = !verbose;
  1009. X        break;
  1010. X
  1011. X     case 'Q':
  1012. X        if (was_raw) raw();
  1013. X        return;
  1014. X    }
  1015. X    }
  1016. X}
  1017. END_OF_FILE
  1018.   if test 21406 -ne `wc -c <'admin.c'`; then
  1019.     echo shar: \"'admin.c'\" unpacked with wrong size!
  1020.   fi
  1021.   # end of 'admin.c'
  1022. fi
  1023. if test -f 'help/help.read' -a "${1}" != "-c" ; then 
  1024.   echo shar: Will not clobber existing file \"'help/help.read'\"
  1025. else
  1026.   echo shar: Extracting \"'help/help.read'\" \(13 characters\)
  1027.   sed "s/^X//" >'help/help.read' <<'END_OF_FILE'
  1028. X;:Chelp.more
  1029. END_OF_FILE
  1030.   if test 13 -ne `wc -c <'help/help.read'`; then
  1031.     echo shar: \"'help/help.read'\" unpacked with wrong size!
  1032.   fi
  1033.   # end of 'help/help.read'
  1034. fi
  1035. if test -f 'inews/inews.c' -a "${1}" != "-c" ; then 
  1036.   echo shar: Will not clobber existing file \"'inews/inews.c'\"
  1037. else
  1038.   echo shar: Extracting \"'inews/inews.c'\" \(8001 characters\)
  1039.   sed "s/^X//" >'inews/inews.c' <<'END_OF_FILE'
  1040. X#ifndef lint
  1041. Xstatic char *sccsid = "@(#)inews.c    1.16    (Berkeley) 8/27/89";
  1042. X#endif
  1043. X
  1044. X/*
  1045. X * Itty-bitty inews for talking to remote server.
  1046. X * Simply accept input on stdin (or via a named file) and dump this
  1047. X * to the server; add a From: and Path: line if missing in the original.
  1048. X * Print meaningful errors from the server.
  1049. X * Limit .signature files to MAX_SIGNATURE lines.
  1050. X * No processing of command line options.
  1051. X *
  1052. X * Original by Steven Grady <grady@ucbvax.Berkeley.EDU>, with thanks from
  1053. X * Phil Lapsley <phil@ucbvax.berkeley.edu>
  1054. X * Send bug reports to Stan Barber <sob@bcm.tmc.edu>
  1055. X */
  1056. X
  1057. X#include <stdio.h>
  1058. X#include <pwd.h>
  1059. X#include <ctype.h>
  1060. X#include "conf.h"
  1061. X#include "nntp.h"
  1062. X#ifndef FOR_NN
  1063. X#ifdef USG
  1064. X#include <string.h>
  1065. X#else not USG
  1066. X#include <strings.h>
  1067. X#endif not USG
  1068. X#endif
  1069. X
  1070. X#define    MAX_SIGNATURE    4
  1071. X
  1072. Xextern    FILE    *ser_wr_fp;
  1073. X
  1074. Xchar    host_name[256];
  1075. X
  1076. Xmain(argc, argv)
  1077. Xint    argc;
  1078. Xchar    *argv[];
  1079. X{
  1080. X    char    line[NNTP_STRLEN], s[NNTP_STRLEN];
  1081. X    int    seen_fromline, in_header, seen_header;
  1082. X    int    response;
  1083. X    char    *server;
  1084. X    char    *getserverbyfile();
  1085. X    register char    *cp;
  1086. X
  1087. X    ++argv;
  1088. X    while (argc > 1)
  1089. X        if (*argv[0] == '-') {
  1090. X            ++argv;
  1091. X            --argc;
  1092. X        } else
  1093. X            break;
  1094. X
  1095. X    if (argc > 1) {
  1096. X        if (freopen(*argv, "r", stdin) == NULL) {
  1097. X            perror(*argv);
  1098. X            exit(1);
  1099. X        }
  1100. X    }
  1101. X
  1102. X    uname(host_name);
  1103. X
  1104. X    server = getserverbyfile(SERVER_FILE);
  1105. X    if (server == NULL) {
  1106. X        fprintf(stderr,
  1107. X            "Can't get the name of the news server from %s.\n",
  1108. X            SERVER_FILE);
  1109. X        fprintf(stderr,
  1110. X           "Either fix this file, or put NNTPSERVER in your enviroment.\n");
  1111. X        exit(1);
  1112. X    }
  1113. X
  1114. X    response = server_init(server);
  1115. X    if (response < 0) {
  1116. X        printf("Couldn't connect to %s news server, try again later.\n",
  1117. X            server);
  1118. X        exit(1);
  1119. X    }
  1120. X
  1121. X    if (handle_server_response(response, server) < 0
  1122. X        || response == OK_NOPOST) {
  1123. X        close_server();
  1124. X        exit(1);
  1125. X    }
  1126. X
  1127. X    put_server("POST");
  1128. X    (void) get_server(line, sizeof(line));
  1129. X    if (*line != CHAR_CONT) {
  1130. X        if (atoi(line) == ERR_NOPOST) {
  1131. X            close_server();
  1132. X            fprintf(stderr,
  1133. X                "Sorry, you can't post from this machine.\n");
  1134. X            exit(1);
  1135. X        } else {
  1136. X            close_server();
  1137. X                fprintf(stderr, "Remote error: %s\n", line);
  1138. X            exit(1);
  1139. X        }
  1140. X    }
  1141. X
  1142. X    in_header = 1;
  1143. X    seen_header = 0;
  1144. X    seen_fromline = 0;
  1145. X
  1146. X    while (gets(s) != NULL) {
  1147. X        if (s[0] == '.')    /* Single . is eof, so put in extra one */
  1148. X            (void) fputc('.', ser_wr_fp);
  1149. X        if (in_header && strneql(s, "From:", sizeof("From:")-1)) {
  1150. X                    seen_header = 1;
  1151. X            seen_fromline = 1;
  1152. X        }
  1153. X        if (in_header && s[0] == '\0') {
  1154. X                    if (seen_header) {
  1155. X                        in_header = 0;
  1156. X                    if (!seen_fromline)
  1157. X                        gen_frompath();
  1158. X            } else {
  1159. X                    continue;
  1160. X            }
  1161. X        } else if (in_header) {
  1162. X                if (valid_header(s))
  1163. X                    seen_header = 1;
  1164. X                    else
  1165. X                                continue;
  1166. X        }
  1167. X        fprintf(ser_wr_fp, "%s\r\n", s);
  1168. X    }
  1169. X
  1170. X    append_signature();
  1171. X
  1172. X    fprintf(ser_wr_fp, ".\r\n");
  1173. X    (void) fflush(ser_wr_fp);
  1174. X    (void) get_server(line, sizeof(line));
  1175. X    if (*line != CHAR_OK) {
  1176. X        if (atoi(line) == ERR_POSTFAIL) {
  1177. X            close_server();
  1178. X            printf("Article not accepted by server; not posted.\n");
  1179. X            for (cp = line + 4; *cp && *cp != '\r'; cp++)
  1180. X                if (*cp == '\\')
  1181. X                    putchar('\n');
  1182. X                else
  1183. X                    putchar(*cp);
  1184. X            exit(1);
  1185. X        } else {
  1186. X            close_server();
  1187. X            fprintf(stderr, "Remote error: %s\n", line);
  1188. X            exit(1);
  1189. X        }
  1190. X    }
  1191. X
  1192. X    /*
  1193. X     * Close server sends the server a
  1194. X     * "quit" command for us, which is why we don't send it.
  1195. X     */
  1196. X
  1197. X    close_server();
  1198. X
  1199. X    exit(0);
  1200. X}
  1201. X
  1202. X/*
  1203. X * append_signature -- append the person's .signature file if
  1204. X * they have one.  Limit .signature to MAX_SIGNATURE lines.
  1205. X * The rn-style DOTDIR environmental variable is used if present.
  1206. X */
  1207. X
  1208. Xappend_signature()
  1209. X{
  1210. X    char    line[256], sigfile[256];
  1211. X    char    *cp;
  1212. X    struct    passwd    *passwd;
  1213. X    FILE    *fp;
  1214. X    char    *index(), *getenv();
  1215. X    int    count = 0;
  1216. X    char    *dotdir;
  1217. X
  1218. X    passwd = getpwuid(getuid());
  1219. X    if (passwd == NULL)
  1220. X      return;
  1221. X#ifdef DO_DOTDIR
  1222. X    if ((dotdir = getenv("DOTDIR")) == NULL)
  1223. X#endif
  1224. X    {
  1225. X      dotdir = passwd->pw_dir;
  1226. X    }
  1227. X
  1228. X    if (dotdir[0] == '~') {
  1229. X      (void) strcpy(sigfile, passwd->pw_dir);
  1230. X      (void) strcat(sigfile, &dotdir[1]);
  1231. X    } else {
  1232. X      (void) strcpy(sigfile, dotdir);
  1233. X    }
  1234. X    (void) strcat(sigfile, "/");
  1235. X    (void) strcat(sigfile, ".signature");
  1236. X
  1237. X#ifdef DEBUG
  1238. X  fprintf(stderr,"sigfile = '%s'\n", sigfile);
  1239. X#endif
  1240. X
  1241. X    fp = fopen(sigfile, "r");
  1242. X    if (fp == NULL)
  1243. X        return;
  1244. X
  1245. X#ifdef DEBUG
  1246. X  fprintf(stderr,"sigfile opened OK\n");
  1247. X#endif
  1248. X
  1249. X    fprintf(ser_wr_fp, "--\r\n");
  1250. X    while (fgets(line, sizeof (line), fp)) {
  1251. X        count++;
  1252. X        if (count > MAX_SIGNATURE) {
  1253. X            fprintf(stderr,
  1254. X          "Warning: .signature files should be no longer than %d lines.\n",
  1255. X            MAX_SIGNATURE);
  1256. X            fprintf(stderr,
  1257. X            "(Only %d lines of your .signature were posted.)\n",
  1258. X            MAX_SIGNATURE);
  1259. X            break;
  1260. X        }
  1261. X        if (cp = index(line, '\n'))
  1262. X            *cp = '\0';
  1263. X        fprintf(ser_wr_fp, "%s\r\n", line);
  1264. X    }
  1265. X    (void) fclose(fp);
  1266. X#ifdef DEBUG
  1267. X    printf(".signature appended (from %s)\n", sigfile);
  1268. X#endif
  1269. X}
  1270. X
  1271. X
  1272. X/*
  1273. X * gen_frompath -- generate From: and Path: lines, in the form
  1274. X *
  1275. X *    From: user@host.domain (full_name)
  1276. X *    Path: host!user
  1277. X *
  1278. X * This routine should only be called if the message doesn't have
  1279. X * a From: line in it.
  1280. X */
  1281. X
  1282. Xgen_frompath()
  1283. X{
  1284. X    char    *full_name;
  1285. X    char    *cp;
  1286. X    struct    passwd *passwd;
  1287. X    char    *index(), *getenv();
  1288. X
  1289. X    passwd = getpwuid(getuid());
  1290. X
  1291. X    full_name = getenv("NAME");
  1292. X    if (full_name == NULL) {
  1293. X        full_name = passwd->pw_gecos;
  1294. X        if ((cp = index(full_name, ',')))
  1295. X            *cp = '\0';
  1296. X    }
  1297. X
  1298. X#ifdef DOMAIN
  1299. X#ifdef HIDDENNET
  1300. X        fprintf(ser_wr_fp, "From: %s@%s (",
  1301. X            passwd->pw_name,
  1302. X            DOMAIN);
  1303. X#else /* HIDDENNET */
  1304. X
  1305. X    /* A heuristic to see if we should tack on a domain */
  1306. X
  1307. X    cp = index(host_name, '.');
  1308. X    if (cp)
  1309. X        fprintf(ser_wr_fp, "From: %s@%s (",
  1310. X            passwd->pw_name,
  1311. X            host_name);
  1312. X    else
  1313. X        fprintf(ser_wr_fp, "From: %s@%s.%s (",
  1314. X            passwd->pw_name,
  1315. X            host_name,
  1316. X            DOMAIN);
  1317. X#endif /* HIDDENNET */
  1318. X#else
  1319. X    fprintf(ser_wr_fp, "From: %s@%s (",
  1320. X        passwd->pw_name,
  1321. X        host_name);
  1322. X#endif
  1323. X
  1324. X    for (cp = full_name; *cp != '\0'; ++cp)
  1325. X        if (*cp != '&')
  1326. X            putc(*cp, ser_wr_fp);
  1327. X        else {        /* Stupid & hack.  God damn it. */
  1328. X            putc(toupper(passwd->pw_name[0]), ser_wr_fp);
  1329. X            fprintf(ser_wr_fp, passwd->pw_name+1);
  1330. X        }
  1331. X
  1332. X    fprintf(ser_wr_fp, ")\r\n");
  1333. X
  1334. X#ifdef HIDDENNET
  1335. X    /* Only the login name - nntp server will add uucp name */
  1336. X    fprintf(ser_wr_fp, "Path: %s\r\n", passwd->pw_name);
  1337. X#else /* HIDDENNET */
  1338. X    fprintf(ser_wr_fp, "Path: %s!%s\r\n", host_name, passwd->pw_name);
  1339. X#endif /* HIDDENNET */
  1340. X}
  1341. X
  1342. X
  1343. X/*
  1344. X * strneql -- determine if two strings are equal in the first n
  1345. X * characters, ignoring case.
  1346. X *
  1347. X *    Parameters:    "a" and "b" are the pointers
  1348. X *            to characters to be compared.
  1349. X *            "n" is the number of characters to compare.
  1350. X *
  1351. X *    Returns:    1 if the strings are equal, 0 otherwise.
  1352. X *
  1353. X *    Side effects:    None.
  1354. X */
  1355. X
  1356. Xstrneql(a, b, n)
  1357. Xregister char *a, *b;
  1358. Xint    n;
  1359. X{
  1360. X    char    lower();
  1361. X
  1362. X    while (n && lower(*a) == lower(*b)) {
  1363. X        if (*a == '\0')
  1364. X            return (1);
  1365. X        a++;
  1366. X        b++;
  1367. X        n--;
  1368. X    }
  1369. X    if (n)
  1370. X        return (0);
  1371. X    else
  1372. X        return (1);
  1373. X}
  1374. X
  1375. X/*
  1376. X * lower -- convert a character to lower case, if it's
  1377. X *    upper case.
  1378. X *
  1379. X *    Parameters:    "c" is the character to be
  1380. X *            converted.
  1381. X *
  1382. X *    Returns:    "c" if the character is not
  1383. X *            upper case, otherwise the lower
  1384. X *            case eqivalent of "c".
  1385. X *
  1386. X *    Side effects:    None.
  1387. X */
  1388. X
  1389. Xchar lower(c)
  1390. Xregister char c;
  1391. X{
  1392. X    if (isascii(c) && isupper(c))
  1393. X        c = c - 'A' + 'a';
  1394. X    return(c);
  1395. X}
  1396. X
  1397. X
  1398. X/*
  1399. X * valid_header -- determine if a line is a valid header line
  1400. X *
  1401. X *    Parameters:    "h" is the header line to be checked.
  1402. X *
  1403. X *    Returns:     1 if valid, 0 otherwise
  1404. X *
  1405. X *    Side Effects:    none
  1406. X *
  1407. X */
  1408. X
  1409. Xint valid_header(h)
  1410. Xregister char *h;
  1411. X{
  1412. X  char *index();
  1413. X  char *colon, *space;
  1414. X
  1415. X  /*
  1416. X   * blank or tab in first position implies this is a continuation header
  1417. X   */
  1418. X  if (h[0] == ' ' || h[0] == '\t')
  1419. X    return (1);
  1420. X
  1421. X  /*
  1422. X   * just check for initial letter, colon, and space to make
  1423. X   * sure we discard only invalid headers
  1424. X   */
  1425. X  colon = index(h, ':');
  1426. X  space = index(h, ' ');
  1427. X  if (isalpha(h[0]) && colon && space == colon + 1)
  1428. X    return (1);
  1429. X
  1430. X  /*
  1431. X   * anything else is a bad header -- it should be ignored
  1432. X   */
  1433. X  return (0);
  1434. X}
  1435. END_OF_FILE
  1436.   if test 8001 -ne `wc -c <'inews/inews.c'`; then
  1437.     echo shar: \"'inews/inews.c'\" unpacked with wrong size!
  1438.   fi
  1439.   # end of 'inews/inews.c'
  1440. fi
  1441. if test -f 'variable.c' -a "${1}" != "-c" ; then 
  1442.   echo shar: Will not clobber existing file \"'variable.c'\"
  1443. else
  1444.   echo shar: Extracting \"'variable.c'\" \(20923 characters\)
  1445.   sed "s/^X//" >'variable.c' <<'END_OF_FILE'
  1446. X/*
  1447. X *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  1448. X *
  1449. X *    Variabel setting and display
  1450. X */
  1451. X
  1452. X#include "config.h"
  1453. X#include "keymap.h"
  1454. X
  1455. Ximport in_init;
  1456. X
  1457. Ximport char            /* string variables */
  1458. X    *bak_suffix,
  1459. X    *bug_address,
  1460. X    *decode_header_file,
  1461. X    *default_distribution,
  1462. X    *default_save_file,
  1463. X    *editor_program,
  1464. X    *extra_mail_headers,
  1465. X    *extra_news_headers,
  1466. X    *header_lines,
  1467. X    *folder_directory,
  1468. X    included_mark[],
  1469. X    *mail_box,
  1470. X    *mail_record,
  1471. X    *mail_script,
  1472. X    *mailer_program,
  1473. X    attributes[],
  1474. X    *newsrc_file,
  1475. X    *news_record,
  1476. X    *news_script,
  1477. X    *pager,
  1478. X    patch_command[],
  1479. X    printer[],
  1480. X    *response_dflt_answer,
  1481. X    *save_counter_format,
  1482. X    *spell_checker,
  1483. X    unshar_command[],
  1484. X    *unshar_header_file,
  1485. X    *user_shell;
  1486. X
  1487. Ximport int            /* boolean variables */
  1488. X    also_cross_postings,
  1489. X    also_subgroups,
  1490. X    append_sig_mail,
  1491. X    append_sig_post,
  1492. X    auto_junk_seen,
  1493. X    auto_preview_mode,
  1494. X    case_fold_search,
  1495. X    compress_mode,
  1496. X    conf_append,
  1497. X    conf_auto_quit,
  1498. X    conf_create,
  1499. X    conf_dont_sleep,
  1500. X    conf_group_entry,
  1501. X    conf_junk_seen,
  1502. X    delay_redraw,
  1503. X    do_kill_handling,
  1504. X    dont_sort_articles,
  1505. X    dont_sort_folders,
  1506. X    dont_split_digests,
  1507. X    edit_patch_command,
  1508. X    edit_print_command,
  1509. X    edit_unshar_command,
  1510. X    empty_answer_check,
  1511. X    flow_control,
  1512. X    flush_typeahead,
  1513. X    fmt_rptsubj,
  1514. X    include_art_id,
  1515. X    include_full_header,
  1516. X    keep_rc_backup,
  1517. X    keep_unsubscribed,
  1518. X    keep_unsub_long,
  1519. X    long_menu,
  1520. X    macro_debug,
  1521. X    mailer_pipe_input,
  1522. X    mark_overlap,
  1523. X    match_parts_equal,
  1524. X    monitor_mode,
  1525. X    novice,
  1526. X    preview_mark_read,
  1527. X    query_signature,
  1528. X    quick_save,
  1529. X    quick_unread_count,
  1530. X    repeat_group_query,
  1531. X    report_cost_on_exit,
  1532. X    retain_seen_status,
  1533. X    save_report,
  1534. X    scroll_clear_page,
  1535. X    select_leave_next,
  1536. X    select_on_sender,
  1537. X    seq_cross_filtering,
  1538. X    shell_restrictions,
  1539. X    show_article_date,
  1540. X    show_current_time,
  1541. X    silent,
  1542. X    slow_mode,
  1543. X    suggest_save_file,
  1544. X    tidy_newsrc,
  1545. X    use_mail_folders,
  1546. X    use_mmdf_folders,
  1547. X    use_selections,
  1548. X    use_visible_bell;
  1549. X
  1550. Ximport int            /* integer variables */
  1551. X    also_read_articles,
  1552. X    article_limit,
  1553. X    conf_entry_limit,
  1554. X    collapse_subject,
  1555. X    Columns,
  1556. X    data_bits,
  1557. X    Debug,
  1558. X    decode_skip_prefix,
  1559. X    entry_message_limit,
  1560. X    expired_msg_delay,
  1561. X    first_page_lines,
  1562. X    fmt_linenum,
  1563. X    Lines,
  1564. X    match_skip_prefix,
  1565. X    min_pv_window,
  1566. X    new_group_action,
  1567. X    newsrc_update_freq,
  1568. X    orig_to_include_mask,
  1569. X    overlap,
  1570. X    preview_continuation,
  1571. X    preview_window,
  1572. X    re_layout,
  1573. X    response_check_pause,
  1574. X    retry_on_error,
  1575. X    save_counter_offset,
  1576. X    slow_speed,
  1577. X    sort_mode,
  1578. X    subject_match_limit,
  1579. X    wrap_headers;
  1580. X
  1581. X#ifdef NNTP
  1582. Ximport char *nntp_cache_dir;
  1583. Ximport int nntp_cache_size, nntp_debug;
  1584. X#endif
  1585. X
  1586. Ximport key_type            /* key strokes */
  1587. X    comp1_key,
  1588. X    comp2_key,
  1589. X    help_key,
  1590. X    erase_key,
  1591. X    delword_key,
  1592. X    kill_key;
  1593. X
  1594. X#undef STR
  1595. X#undef BOOL
  1596. X#undef INT
  1597. X#undef KEY
  1598. X#undef SPEC
  1599. X#undef SAFE
  1600. X#undef INIT
  1601. X
  1602. X
  1603. X#define    V_STRING    0x1000
  1604. X#define V_BOOLEAN    0x2000
  1605. X#define    V_INTEGER    0x3000
  1606. X#define V_KEY        0x4000
  1607. X#define    V_SPECIAL    0x5000
  1608. X
  1609. X#define V_SAFE        0x0100
  1610. X#define V_INIT        0x0200
  1611. X
  1612. X#define V_MODIFIED    0x8000
  1613. X
  1614. X#define    STR        V_STRING |
  1615. X#define BOOL        V_BOOLEAN |
  1616. X#define    INT        V_INTEGER |
  1617. X#define KEY        V_KEY |
  1618. X#define    SPEC        V_SPECIAL |
  1619. X
  1620. X#define SAFE        V_SAFE |
  1621. X#define INIT        V_INIT |
  1622. X
  1623. Xstruct variable_defs {
  1624. X    char *var_name;
  1625. X    int  var_flags;
  1626. X    char **var_addr;
  1627. X} variables[] = {
  1628. X    "also-subgroups",        BOOL INIT 0,    (char **)&also_subgroups,
  1629. X    "append-signature-mail",     BOOL 0,        (char **)&append_sig_mail,
  1630. X    "append-signature-post",     BOOL 0,        (char **)&append_sig_post,
  1631. X    "attributes",        STR 1,        (char **)attributes,
  1632. X    "auto-junk-seen",        BOOL 0,        (char **)&auto_junk_seen,
  1633. X    "auto-preview-mode",    BOOL 0,        (char **)&auto_preview_mode,
  1634. X    "backup",            BOOL 0,        (char **)&keep_rc_backup,
  1635. X    "backup-suffix",        STR 0,        (char **)&bak_suffix,
  1636. X    "bug-report-address",     STR 0,        (char **)&bug_address,
  1637. X    "case-fold-search",        BOOL 0,        (char **)&case_fold_search,
  1638. X    "collapse-subject",        INT 3,        (char **)&collapse_subject,
  1639. X    "columns",            INT 1,        (char **)&Columns,
  1640. X    "comp1-key",        KEY 0,        (char **)&comp1_key,
  1641. X    "comp2-key",        KEY 0,        (char **)&comp2_key,
  1642. X    "compress",            BOOL 0,        (char **)&compress_mode,
  1643. X    "confirm-append",        BOOL 0,        (char **)&conf_append,
  1644. X    "confirm-auto-quit",    BOOL 0,        (char **)&conf_auto_quit,
  1645. X    "confirm-create",        BOOL 0,        (char **)&conf_create,
  1646. X    "confirm-entry",        BOOL 0,        (char **)&conf_group_entry,
  1647. X    "confirm-entry-limit",    INT 0,        (char **)&conf_entry_limit,
  1648. X    "confirm-junk-seen",     BOOL 0,        (char **)&conf_junk_seen,
  1649. X    "confirm-messages",        BOOL 0,        (char **)&conf_dont_sleep,
  1650. X    "cross-filter-seq",        BOOL 0,        (char **)&seq_cross_filtering,
  1651. X    "cross-post",        BOOL 0,        (char **)&also_cross_postings,
  1652. X    "data-bits",        INT 0,        (char **)&data_bits,
  1653. X    "date",            BOOL 0,        (char **)&show_article_date,
  1654. X    "debug",            INT 0,        (char **)&Debug,
  1655. X    "decode-header-file",    STR 0,        (char **)&decode_header_file,
  1656. X    "decode-skip-prefix",    INT 0,        (char **)&decode_skip_prefix,
  1657. X    "default-distribution",    STR 0,        (char **)&default_distribution,
  1658. X    "default-save-file",    STR 3,        (char **)&default_save_file,
  1659. X    "delay-redraw",        BOOL 0,        (char **)&delay_redraw,
  1660. X    "edit-patch-command",     BOOL 0,        (char **)&edit_patch_command,
  1661. X    "edit-print-command",     BOOL 0,        (char **)&edit_print_command,
  1662. X    "edit-response-check",     BOOL 0,        (char **)&empty_answer_check,
  1663. X    "edit-unshar-command",     BOOL 0,        (char **)&edit_unshar_command,
  1664. X    "editor",            STR 0,        (char **)&editor_program,
  1665. X    "entry-report-limit",     INT 0,        (char **)&entry_message_limit,
  1666. X    "erase-key",        KEY 0,        (char **)&erase_key,
  1667. X    "expert",            BOOL 4,        (char **)&novice,
  1668. X    "expired-message-delay",    INT 0,        (char **)&expired_msg_delay,
  1669. X    "flow-control",        BOOL 0,        (char **)&flow_control,
  1670. X    "flush-typeahead",        BOOL 0,        (char **)&flush_typeahead,
  1671. X    "folder",            STR 2,        (char **)&folder_directory,
  1672. X    "fsort",            BOOL 2,        (char **)&dont_sort_folders,
  1673. X    "header-lines",        STR 0,        (char **)&header_lines,
  1674. X    "help-key",            KEY 0,        (char **)&help_key,
  1675. X    "include-art-id",        BOOL 0,        (char **)&include_art_id,
  1676. X    "include-full-header",    BOOL 0,        (char **)&include_full_header,
  1677. X    "included-mark",        STR 1,        (char **)included_mark,
  1678. X    "keep-unsubscribed",     BOOL 0,        (char **)&keep_unsubscribed,
  1679. X    "kill",            BOOL 0,        (char **)&do_kill_handling,
  1680. X    "kill-key",            KEY 0,        (char **)&kill_key,
  1681. X    "layout",            INT 1,        (char **)&fmt_linenum,
  1682. X    "limit",            INT 2,        (char **)&article_limit,
  1683. X    "lines",            INT 1,        (char **)&Lines,
  1684. X    "long-menu",        BOOL 1,        (char **)&long_menu,
  1685. X    "macro-debug",        BOOL 0,        (char **)¯o_debug,
  1686. X    "mail",            STR 2,        (char **)&mail_box,
  1687. X    "mail-format",        BOOL 0,        (char **)&use_mail_folders,
  1688. X    "mail-header",        STR 0,        (char **)&extra_mail_headers,
  1689. X    "mail-record",        STR 2,        (char **)&mail_record,
  1690. X    "mail-script",        STR SAFE 2,    (char **)&mail_script,
  1691. X    "mailer",            STR 0,        (char **)&mailer_program,
  1692. X    "mailer-pipe-input",    BOOL 0,        (char **)&mailer_pipe_input,
  1693. X    "mark-overlap",        BOOL 0,        (char **)&mark_overlap,
  1694. X    "min-window",        INT 1,        (char **)&min_pv_window,
  1695. X    "mmdf-format",        BOOL 0,        (char **)&use_mmdf_folders,
  1696. X    "monitor",            BOOL 0,        (char **)&monitor_mode,
  1697. X    "new-group-action",        INT 0,        (char **)&new_group_action,
  1698. X    "news-header",        STR 0,        (char **)&extra_news_headers,
  1699. X    "news-record",        STR 2,        (char **)&news_record,
  1700. X    "news-script",        STR SAFE 2,    (char **)&news_script,
  1701. X    "newsrc",            STR 2,        (char **)&newsrc_file,
  1702. X#ifdef NNTP
  1703. X    "nntp-cache-dir",        STR INIT 0,    (char **)&nntp_cache_dir,
  1704. X    "nntp-cache-size",        INT INIT 0,    (char **)&nntp_cache_size,
  1705. X    "nntp-debug",        BOOL 0,        (char **)&nntp_debug,
  1706. X#endif
  1707. X/*  "no....."  -- cannot have variable names starting with "no" */
  1708. X    "old",            SPEC 2,        (char **)NULL,
  1709. X    "orig-to-include-mask",    INT 0,        (char **)&orig_to_include_mask,
  1710. X    "overlap",            INT 0,        (char **)&overlap,
  1711. X    "pager",            STR SAFE 3,    (char **)&pager,
  1712. X    "patch-command",        STR SAFE 1,    (char **)patch_command,
  1713. X    "preview-continuation",     INT 0,        (char **)&preview_continuation,
  1714. X    "preview-mark-read",    BOOL 0,        (char **)&preview_mark_read,
  1715. X    "printer",            STR SAFE 1,    (char **)printer,
  1716. X    "query-signature",        BOOL 0,        (char **)&query_signature,
  1717. X    "quick-count",        BOOL 0,        (char **)&quick_unread_count,
  1718. X    "quick-save",        BOOL 0,        (char **)&quick_save,
  1719. X    "re-layout",        INT 0,        (char **)&re_layout,
  1720. X    "record",            SPEC 1,        (char **)NULL,
  1721. X    "repeat",            BOOL 0,        (char **)&fmt_rptsubj,
  1722. X    "repeat-group-query",    BOOL 0,        (char **)&repeat_group_query,
  1723. X    "report-cost",        BOOL 0,        (char **)&report_cost_on_exit,
  1724. X    "response-check-pause",    INT 0,        (char **)&response_check_pause,
  1725. X    "response-default-answer",    STR 0,        (char **)&response_dflt_answer,
  1726. X    "retain-seen-status",     BOOL 0,        (char **)&retain_seen_status,
  1727. X    "retry-on-error",        INT 0,        (char **)&retry_on_error,
  1728. X    "save-counter",        STR 3,        (char **)&save_counter_format,
  1729. X    "save-counter-offset",    INT 0,        (char **)&save_counter_offset,
  1730. X    "save-report",        BOOL 0,        (char **)&save_report,
  1731. X    "scroll-clear-page",    BOOL 0,        (char **)&scroll_clear_page,
  1732. X    "select-leave-next",    BOOL 0,        (char **)&select_leave_next,
  1733. X    "select-on-sender",        BOOL 0,        (char **)&select_on_sender,
  1734. X    "shell",            STR SAFE 0,    (char **)&user_shell,
  1735. X    "shell-restrictions",     BOOL INIT 0,    (char **)&shell_restrictions,
  1736. X    "silent",            BOOL 0,        (char **)&silent,
  1737. X    "slow-mode",        BOOL 0,        (char **)&slow_mode,
  1738. X    "slow-speed",        INT 0,        (char **)&slow_speed,
  1739. X    "sort",            BOOL 2,        (char **)&dont_sort_articles,
  1740. X    "sort-mode",        INT 0,        (char **)&sort_mode,
  1741. X    "spell-checker",        STR 0,        (char **)&spell_checker,
  1742. X    "split",            BOOL 4,        (char **)&dont_split_digests,
  1743. X    "stop",            INT 0,        (char **)&first_page_lines,
  1744. X    "subject-match-limit",     INT 0,        (char **)&subject_match_limit,
  1745. X    "subject-match-offset",    INT 0,        (char **)&match_skip_prefix,
  1746. X    "subject-match-parts",    BOOL 0,        (char **)&match_parts_equal,
  1747. X    "suggest-default-save",     BOOL 0,        (char **)&suggest_save_file,
  1748. X    "tidy-newsrc",        BOOL 0,        (char **)&tidy_newsrc,
  1749. X    "time",            BOOL 0,        (char **)&show_current_time,
  1750. X    "unshar-command",        STR SAFE 1,    (char **)unshar_command,
  1751. X    "unshar-header-file",    STR 0,        (char **)&unshar_header_file,
  1752. X    "unsubscribe-mark-read",    BOOL 4,        (char **)&keep_unsub_long,
  1753. X    "update-frequency",        INT 0,        (char **)&newsrc_update_freq,
  1754. X    "use-selections",         BOOL 0,        (char **)&use_selections,
  1755. X    "visible-bell",         BOOL 0,        (char **)&use_visible_bell,
  1756. X    "window",            INT 1,        (char **)&preview_window,
  1757. X    "word-key",            KEY 0,        (char **)&delword_key,
  1758. X    "wrap-header-margin",    INT 2,        (char **)&wrap_headers
  1759. X};
  1760. X
  1761. X#define TABLE_SIZE    (sizeof(variables)/sizeof(struct variable_defs))
  1762. X
  1763. X#define INT_VAR        (*((int *)(var->var_addr)))
  1764. X#define BOOL_VAR    (*((int *)(var->var_addr)))
  1765. X#define STR_VAR        (*(var->var_addr))
  1766. X#define CBUF_VAR    ((char *)(var->var_addr))
  1767. X#define KEY_VAR        (*((key_type *)(var->var_addr)))
  1768. X
  1769. X#define VAR_TYPE    (var->var_flags & 0x7000)
  1770. X#define VAR_OP        (var->var_flags & 0x000f)
  1771. X
  1772. Xstatic struct variable_defs *lookup_variable(variable)
  1773. Xchar *variable;
  1774. X{
  1775. X    register struct variable_defs *var;
  1776. X    register i, j, k, t;
  1777. X
  1778. X    i = 0; j = TABLE_SIZE - 1;
  1779. X
  1780. X    while (i <= j) {
  1781. X    k = (i + j) / 2;
  1782. X    var = &variables[k];
  1783. X
  1784. X    if ( (t=strcmp(variable, var->var_name)) > 0)
  1785. X        i = k+1;
  1786. X    else
  1787. X    if (t < 0)
  1788. X        j = k-1;
  1789. X    else
  1790. X        return var;
  1791. X    }
  1792. X
  1793. X    init_message("unknown variable: %s", variable);
  1794. X    return NULL;
  1795. X}
  1796. X
  1797. X
  1798. Xstatic adjust(str)
  1799. Xregister char *str;
  1800. X{
  1801. X    if (str == NULL) return;
  1802. X    while (*str && !isspace(*str) && *str != '#') str++;
  1803. X    *str = NUL;
  1804. X}
  1805. X
  1806. Xset_variable(variable, on, val_string)
  1807. Xchar *variable;
  1808. Xint on;
  1809. Xchar *val_string;
  1810. X{
  1811. X    int value;
  1812. X    register struct variable_defs *var;
  1813. X
  1814. X    if (strncmp(variable, "no", 2) == 0) {
  1815. X    on = !on;
  1816. X    variable += 2;
  1817. X    if (variable[0] == '-') variable++;
  1818. X    }
  1819. X
  1820. X    if ((var = lookup_variable(variable)) == NULL)
  1821. X    return 0;
  1822. X
  1823. X    if (!in_init && (var->var_flags & (V_INIT | V_SAFE))) {
  1824. X    if (var->var_flags & V_INIT) {
  1825. X        msg("'%s' can only be set in the init file", variable);
  1826. X        return 0;
  1827. X    }
  1828. X    if (shell_restrictions) {
  1829. X        msg("Restricted operation - cannot change");
  1830. X        return 0;
  1831. X    }
  1832. X    }
  1833. X
  1834. X    if (!on || val_string == NULL)
  1835. X    value = 0;
  1836. X    else
  1837. X    value = atoi(val_string);
  1838. X
  1839. X    var->var_flags |= V_MODIFIED;
  1840. X
  1841. X    switch (VAR_TYPE) {
  1842. X
  1843. X     case V_STRING:
  1844. X
  1845. X    switch (VAR_OP) {
  1846. X     case 0:
  1847. X        STR_VAR = (on && val_string) ? copy_str(val_string) : (char *)NULL;
  1848. X        break;
  1849. X
  1850. X     case 1:
  1851. X        strcpy(CBUF_VAR, (on && val_string) ? val_string : "");
  1852. X        break;
  1853. X
  1854. X     case 2:
  1855. X        if (on) {
  1856. X        char exp_buf[FILENAME];
  1857. X
  1858. X        adjust(val_string);
  1859. X        if (val_string) {
  1860. X            if (expand_file_name(exp_buf, val_string, 1))
  1861. X            STR_VAR = home_relative(exp_buf);
  1862. X        }
  1863. X        } else
  1864. X        STR_VAR = (char *)NULL;
  1865. X        break;
  1866. X
  1867. X     case 3:
  1868. X        if (!on || val_string == NULL) {
  1869. X        msg("Cannot unset string `%s'", variable);
  1870. X        break;
  1871. X        }
  1872. X        STR_VAR = copy_str(val_string);
  1873. X        break;
  1874. X    }
  1875. X    break;
  1876. X
  1877. X     case V_BOOLEAN:
  1878. X
  1879. X    if (val_string)
  1880. X        if (val_string[0] == 'o')
  1881. X        on = val_string[1] == 'n'; /* on */
  1882. X        else
  1883. X        on = val_string[0] == 't'; /* true */
  1884. X
  1885. X    switch (VAR_OP) {
  1886. X     case 0:
  1887. X        BOOL_VAR = on;
  1888. X        break;
  1889. X
  1890. X     case 1:
  1891. X        BOOL_VAR = on;
  1892. X        return 1;
  1893. X
  1894. X     case 2:
  1895. X        if (BOOL_VAR == on) {
  1896. X        BOOL_VAR = !on;
  1897. X        if (!in_init) {
  1898. X            sort_articles(BOOL_VAR ? 0 : -1);
  1899. X            return 1;
  1900. X        }
  1901. X        }
  1902. X        break;
  1903. X
  1904. X     case 4:
  1905. X        BOOL_VAR = !on;
  1906. X        break;
  1907. X    }
  1908. X    break;
  1909. X
  1910. X     case V_INTEGER:
  1911. X
  1912. X    switch (VAR_OP) {
  1913. X     case 0:
  1914. X     case 1:
  1915. X        INT_VAR = value;
  1916. X        break;
  1917. X
  1918. X     case 2:
  1919. X     case 3:
  1920. X        if (!on) value = -1;
  1921. X        INT_VAR = value;
  1922. X        break;
  1923. X    }
  1924. X    return (VAR_OP & 1);
  1925. X
  1926. X     case V_KEY:
  1927. X    switch (VAR_OP) {
  1928. X     case 0:
  1929. X        if (val_string) {
  1930. X        if (*val_string) adjust(val_string + 1); /* #N is valid */
  1931. X        KEY_VAR = parse_key(val_string);
  1932. X        }
  1933. X        break;
  1934. X    }
  1935. X    break;
  1936. X
  1937. X     case V_SPECIAL:
  1938. X
  1939. X    switch (VAR_OP) {
  1940. X     case 1:
  1941. X        if (val_string) {
  1942. X        adjust(val_string);
  1943. X        news_record = home_relative(val_string);
  1944. X        mail_record = news_record;
  1945. X        }
  1946. X        break;
  1947. X
  1948. X     case 2:
  1949. X        also_read_articles = on;
  1950. X        article_limit = (on && value > 0) ? value : -1;
  1951. X        break;
  1952. X    }
  1953. X    break;
  1954. X    }
  1955. X    return 0;
  1956. X}
  1957. X
  1958. Xtoggle_variable(variable)
  1959. Xchar *variable;
  1960. X{
  1961. X    register struct variable_defs *var;
  1962. X
  1963. X    if ((var = lookup_variable(variable)) == NULL) return;
  1964. X    if (VAR_TYPE != V_BOOLEAN) {
  1965. X    init_message("variable %s is not boolean", variable);
  1966. X    return;
  1967. X    }
  1968. X
  1969. X    BOOL_VAR = !BOOL_VAR;
  1970. X}
  1971. X
  1972. X
  1973. Xtest_variable(expr)
  1974. Xchar *expr;
  1975. X{
  1976. X    char *variable;
  1977. X    register struct variable_defs *var;
  1978. X    int res = -1;
  1979. X
  1980. X    variable = expr;
  1981. X    if ((expr = strchr(variable, '=')) == NULL)
  1982. X    goto err;
  1983. X
  1984. X    *expr++ = NUL;
  1985. X
  1986. X    if ((var = lookup_variable(variable)) == NULL) {
  1987. X    msg("testing unknown variable %s=%s", variable, expr);
  1988. X    goto out;
  1989. X    }
  1990. X
  1991. X    switch (VAR_TYPE) {
  1992. X
  1993. X     case V_BOOLEAN:
  1994. X    res = BOOL_VAR;
  1995. X
  1996. X    if (strcmp(expr, "on") == 0 || strcmp(expr, "true") == 0) break;
  1997. X    if (strcmp(expr, "off") == 0 || strcmp(expr, "false") == 0) {
  1998. X        res = !res;
  1999. X        break;
  2000. X    }
  2001. X    msg("boolean variables must be tested =on or =off");
  2002. X    break;
  2003. X
  2004. X     case V_INTEGER:
  2005. X    res = (INT_VAR == atoi(expr)) ? 1 : 0;
  2006. X    break;
  2007. X
  2008. X     default:
  2009. X    msg("%s: cannot only test boolean and integer variables", variable);
  2010. X    break;
  2011. X    }
  2012. X out:
  2013. X    *--expr = '=';
  2014. X err:
  2015. X    return res;
  2016. X}
  2017. X
  2018. X
  2019. Xvar_completion(path, index)
  2020. Xchar *path;
  2021. Xint index;
  2022. X{
  2023. X    static char *head, *tail = NULL;
  2024. X    static int len;
  2025. X    static struct variable_defs *var, *help_var;
  2026. X
  2027. X    if (index < 0) return 0;
  2028. X
  2029. X    if (path) {
  2030. X    head = path;
  2031. X    tail = path + index;
  2032. X    while (*head && isspace(*head)) head++;
  2033. X    if (strncmp(head, "no", 2) == 0) {
  2034. X        head += 2;
  2035. X        if (*head == '-') head++;
  2036. X    }
  2037. X
  2038. X    help_var = var = variables;
  2039. X    len = tail - head;
  2040. X
  2041. X    return 1;
  2042. X    }
  2043. X
  2044. X    if (index) {
  2045. X    list_completion((char *)NULL);
  2046. X
  2047. X    for (;; help_var++) {
  2048. X        if (help_var >= &variables[TABLE_SIZE]) {
  2049. X        help_var = variables;
  2050. X        break;
  2051. X        }
  2052. X
  2053. X        index = strncmp(help_var->var_name, head, len);
  2054. X        if (index < 0) continue;
  2055. X        if (index > 0) {
  2056. X        help_var = variables;
  2057. X        break;
  2058. X        }
  2059. X        if (list_completion(help_var->var_name) == 0) break;
  2060. X    }
  2061. X    fl;
  2062. X    return 1;
  2063. X    }
  2064. X
  2065. X    for (; var < &variables[TABLE_SIZE]; var++) {
  2066. X    if (len == 0)
  2067. X        index = 0;
  2068. X    else
  2069. X        index = strncmp(var->var_name, head, len);
  2070. X    if (index < 0) continue;
  2071. X    if (index > 0) break;
  2072. X    sprintf(tail, "%s ", var->var_name + len);
  2073. X    var++;
  2074. X    return 1;
  2075. X    }
  2076. X    return 0;
  2077. X}
  2078. X
  2079. Xstatic struct var_stack {
  2080. X    struct var_stack *next;
  2081. X    struct variable_defs *v;
  2082. X    int mod_flag;
  2083. X    union {
  2084. X    int ivar;
  2085. X    int bool;
  2086. X    char key;
  2087. X    char *str;
  2088. X    } value;
  2089. X} *var_stack = NULL, *vs_pool = NULL;
  2090. X
  2091. Xmark_var_stack()
  2092. X{
  2093. X    register struct var_stack *vs;
  2094. X
  2095. X    if (vs_pool) {
  2096. X    vs = vs_pool;
  2097. X    vs_pool = vs->next;
  2098. X    } else
  2099. X    vs = newobj(struct var_stack, 1);
  2100. X
  2101. X    vs->next = var_stack;
  2102. X    var_stack = vs;
  2103. X    vs->v = NULL;
  2104. X}
  2105. X
  2106. Xpush_variable(variable)
  2107. Xchar *variable;
  2108. X{
  2109. X    register struct variable_defs *var;
  2110. X    register struct var_stack *vs;
  2111. X
  2112. X    if (strncmp(variable, "no", 2) == 0) {
  2113. X    variable += 2;
  2114. X    if (variable[0] == '-') variable++;
  2115. X    }
  2116. X
  2117. X    if ((var = lookup_variable(variable)) == NULL) {
  2118. X    msg("pushing unknown variable %s", variable);
  2119. X    return 0;
  2120. X    }
  2121. X
  2122. X    mark_var_stack();
  2123. X    vs = var_stack;
  2124. X    vs->v = var;
  2125. X    vs->mod_flag = var->var_flags & V_MODIFIED;
  2126. X
  2127. X    switch (VAR_TYPE) {
  2128. X
  2129. X     case V_STRING:
  2130. X
  2131. X    switch (VAR_OP) {
  2132. X     case 0:    /* if we update one of these variables,    */
  2133. X     case 2:    /* new storage will be allocated for it */
  2134. X     case 3:    /* so it is ok just to save the pointer */
  2135. X        vs->value.str = STR_VAR;
  2136. X        break;
  2137. X
  2138. X     case 1:    /* we free this memory when restored    */
  2139. X        vs->value.str = copy_str(CBUF_VAR);
  2140. X        break;
  2141. X    }
  2142. X    break;
  2143. X
  2144. X     case V_BOOLEAN:
  2145. X    vs->value.bool = BOOL_VAR;
  2146. X    break;
  2147. X
  2148. X     case V_INTEGER:
  2149. X    vs->value.ivar = INT_VAR;
  2150. X    break;
  2151. X
  2152. X     case V_KEY:
  2153. X    vs->value.key = KEY_VAR;
  2154. X    break;
  2155. X
  2156. X     case V_SPECIAL:
  2157. X    msg("Cannot push pseudo variable %s", var->var_name);
  2158. X    break;
  2159. X    }
  2160. X
  2161. X    return 1;
  2162. X}
  2163. X
  2164. Xrestore_variables()
  2165. X{
  2166. X    register struct variable_defs *var;
  2167. X    register struct var_stack *vs, *vs1;
  2168. X
  2169. X    vs = var_stack;
  2170. X
  2171. X    while (vs != NULL) {
  2172. X    if ((var = vs->v) == NULL) {
  2173. X        var_stack = vs->next;
  2174. X        vs->next = vs_pool;
  2175. X        vs_pool = vs;
  2176. X        return;
  2177. X    }
  2178. X
  2179. X    var->var_flags &= ~V_MODIFIED;
  2180. X    var->var_flags |= vs->mod_flag;
  2181. X
  2182. X    switch (VAR_TYPE) {
  2183. X
  2184. X     case V_STRING:
  2185. X        switch (VAR_OP) {
  2186. X         case 0:    /* only restore the string if changed; then we    */
  2187. X         case 2:    /* can also free the memory occupied by the    */
  2188. X         case 3:    /* 'new' value (if not NULL)            */
  2189. X        if (STR_VAR != vs->value.str) {
  2190. X            if (STR_VAR != NULL) freeobj(STR_VAR);
  2191. X            STR_VAR = vs->value.str;
  2192. X        }
  2193. X        break;
  2194. X
  2195. X         case 1:    /* it fitted before, so it will fit againg */
  2196. X        strcpy(CBUF_VAR, vs->value.str);
  2197. X        freeobj(vs->value.str);
  2198. X        break;
  2199. X        }
  2200. X        break;
  2201. X
  2202. X     case V_BOOLEAN:
  2203. X        BOOL_VAR = vs->value.bool;
  2204. X        break;
  2205. X
  2206. X     case V_INTEGER:
  2207. X        INT_VAR = vs->value.ivar;
  2208. X        break;
  2209. X
  2210. X     case V_KEY:
  2211. X        KEY_VAR = vs->value.key;
  2212. X        break;
  2213. X
  2214. X     case V_SPECIAL:    /* these are not saved, so... */
  2215. X        break;
  2216. X    }
  2217. X
  2218. X    vs1 = vs->next;
  2219. X    vs->next = vs_pool;
  2220. X    vs_pool = vs;
  2221. X    vs = vs1;
  2222. X    }
  2223. X    var_stack = NULL;
  2224. X}
  2225. X
  2226. Xstatic var_on_stack(var)
  2227. Xregister struct variable_defs *var;
  2228. X{
  2229. X    register struct var_stack *vs;
  2230. X
  2231. X    for (vs = var_stack; vs; vs = vs->next)
  2232. X    if (vs->v == var) return 1;
  2233. X    return 0;
  2234. X}
  2235. X
  2236. Xdisp_variables(all)
  2237. Xint all;
  2238. X{
  2239. X    char *str, pushed;
  2240. X    int b;
  2241. X    register struct variable_defs *var;
  2242. X
  2243. X    if (in_init) return;
  2244. X
  2245. X    pg_init(0, 1);
  2246. X
  2247. X    clrdisp();
  2248. X    if (novice && !all) {
  2249. X    msg("Use `:set all' to see all variable settings");
  2250. X    home();
  2251. X    }
  2252. X    pg_next();
  2253. X    so_printf("\1Variable settings:\1");
  2254. X
  2255. X    for (var = variables; var < &variables[TABLE_SIZE]; var++) {
  2256. X    pushed =
  2257. X        var_on_stack(var) ? '>' :
  2258. X        (var->var_flags & V_MODIFIED) ? '*' : ' ';
  2259. X
  2260. X    if (!all && pushed == ' ') continue;
  2261. X
  2262. X    switch (VAR_TYPE) {
  2263. X     case V_STRING:
  2264. X        if (pg_next() < 0) goto out;
  2265. X        str = (VAR_OP == 1) ? CBUF_VAR : STR_VAR;
  2266. X        if (str == NULL) str = "";
  2267. X        printf("%c %-20.20s = \"%s\"\n", pushed, var->var_name, str);
  2268. X        break;
  2269. X
  2270. X     case V_BOOLEAN:
  2271. X        if (pg_next() < 0) goto out;
  2272. X        b = BOOL_VAR;
  2273. X        if (VAR_OP == 2 || VAR_OP == 4) b = !b;
  2274. X        printf("%c %-20.20s = %s\n",
  2275. X           pushed, var->var_name, b ? "on" : "off");
  2276. X        break;
  2277. X
  2278. X     case V_INTEGER:
  2279. X        if (pg_next() < 0) goto out;
  2280. X        printf("%c %-20.20s = %d\n", pushed, var->var_name, INT_VAR);
  2281. X        break;
  2282. X
  2283. X     case V_KEY:
  2284. X        if (pg_next() < 0) goto out;
  2285. X        printf("%c %-20.20s = %s\n",
  2286. X           pushed, var->var_name, key_name(KEY_VAR));
  2287. X        break;
  2288. X
  2289. X     case V_SPECIAL:
  2290. X        switch (VAR_OP) {
  2291. X         case 1:
  2292. X        break;
  2293. X         case 2:
  2294. X        if (also_read_articles) {
  2295. X            if (pg_next() < 0) goto out;
  2296. X            printf("%c %-20.20s = %d\n",
  2297. X               pushed, var->var_name, article_limit);
  2298. X        }
  2299. X        break;
  2300. X        }
  2301. X        break;
  2302. X    }
  2303. X    }
  2304. X
  2305. Xout:
  2306. X    pg_end();
  2307. X}
  2308. END_OF_FILE
  2309.   if test 20923 -ne `wc -c <'variable.c'`; then
  2310.     echo shar: \"'variable.c'\" unpacked with wrong size!
  2311.   fi
  2312.   # end of 'variable.c'
  2313. fi
  2314. echo shar: End of archive 12 \(of 22\).
  2315. cp /dev/null ark12isdone
  2316. MISSING=""
  2317. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
  2318.     if test ! -f ark${I}isdone ; then
  2319.     MISSING="${MISSING} ${I}"
  2320.     fi
  2321. done
  2322. if test "${MISSING}" = "" ; then
  2323.     echo You have unpacked all 22 archives.
  2324.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2325. else
  2326.     echo You still must unpack the following archives:
  2327.     echo "        " ${MISSING}
  2328. fi
  2329. exit 0
  2330.  
  2331. exit 0 # Just in case...
  2332.